#include "sslserver.hpp"
#include<unordered_map>
#include<mutex>
#include<string>
#include<string.h>
static const unsigned int accountlen=4,client_login_failed=0,
client_login_success=1;
static std::mutex lock;
SSLServer::ThreadInfo* holder=nullptr;
class MyServer:public SSLServer{
	typedef struct Vector3f{
		float x,y,z;
	}Vector3f;
	typedef struct Transform{
		Vector3f position,rotation;
	}Transform;
	typedef struct User{
		char password[16];
		Transform transform;
		const char* name;
	}User;
	typedef struct Account{
		char account[accountlen],password[16];
	}Account;
	typedef struct LoginStatus{
		ThreadInfo* belong;
		Account account;
		bool processed;
	}LoginStatus;
	std::unordered_map<std::string,User> users{
		{"0001",User{{"123456\0\0\0\0\0\0\0\0\0"},{{0.,0.,0.},{0.,0.,0.}},"小明"}},
		{"0002",User{{"123456\0\0\0\0\0\0\0\0\0"},{{0.,0.,0.},{0.,0.,0.}},"小红"}}
	};
	std::unordered_map<DataInfo*,User*> onlines;
	std::unordered_map<DataInfo*,LoginStatus*> status;
	static void userexit(MyServer* s,ThreadInfo* from,DataInfo* info,void* arg){
		auto& m=s->onlines;
		while(!lock.try_lock())sleep();
		auto f=m.find(info);
		if(f!=m.end()){
			printf("%s logout\n",f->second->name);
			m.erase(f);
		}
		lock.unlock();
	}
	static bool onlogin(MyServer* s,ThreadInfo* from,DataInfo* info,void* arg){
		printf("on login\n");
		s->resettime(info);
		auto status=(LoginStatus*)arg;
		std::string acc(status->account.account,accountlen);
		auto& m=s->users;
		auto belong=status->belong;
		if(from!=holder)while(!lock.try_lock())sleep();
		holder=from;
		auto f=m.find(acc);
		if(f!=m.end()){
			if(!memcmp(status->account.password,f->second.password,16)){
				s->onlines.emplace(info,&f->second);
				printf("%s login\n",f->second.name);
				status->processed=true;
				if(from!=holder)lock.unlock();
				s->senddata(from,info,{(char*)&client_login_success,1,emptysendback,0});
				return true;
			}
		}
		status->processed=true;
		if(from!=holder)lock.unlock();
		s->senddata(from,info,{(char*)&client_login_failed,1,emptysendback,0});
		return true;
	}
	static bool entry(MyServer* s,ThreadInfo* from,DataInfo* info,void* arg){
		switch(*s->getbuffer(info)){
			case 0:s->resettime(info);return true;//心跳帧
			case 1:{//登录
				printf("login requested\n");
				auto& m=s->status;
				LoginStatus* status;
				if(holder!=from)while(!lock.try_lock())sleep();
				holder=from;
				auto f=m.find(info);
				if(f!=m.end())status=f->second;else status=new LoginStatus{from,{0},true};
				if(status->processed){
					s->resettime(info);
					status->processed=false;
					s->recvdata(from,info,{(char*)&status->account,
					sizeof(Account),(DataCallback)onlogin,status});
				}
				lock.unlock();
			}
		}
		return true;
	}
	public:
	int run(const char* address,unsigned int port){
		if(openlib()){
			auto ret=SSLServer::run("./privatekey.pem","./cert.crt",address,port,
			1,(DataCallback)entry,this,(LostCallback)userexit,this);
			closelib();
			return ret;
		}
		return -1;
	}
	~MyServer(){for(auto v:status)delete v.second;}
};

int main(){
	return MyServer().run("127.0.0.1",8888);
}